<cfcomponent output="false" extends="BaseTest">
<cfscript>

 null = chr(0);

function simpleEncoderTest(){
  encoder = createObject('component', 'cfesapi.org.owasp.esapi.Encoder').init();
  evilString = '<script>alert("punk")</script>';
  html = encoder.encodeForHtml(evilString);
  writeoutput(html);
  u = encoder.encodeForURL(evilString);
  writeoutput(u);
  notSafe = encoder.decodeFromURL(evilString);
  writeoutput( encoder.encodeForHtml(notSafe) );
 }


  function encoderShouldReturnSelf() {
     assertSame( encoder, encoder );
  }


 function testEncodeForBase64() {
   debug("encodeForBase64");

    assertEquals(null, instance.encodeForBase64(null.getBytes(), false));
    assertEquals(null, instance.encodeForBase64(null.getBytes(), true));

    s = 'Kwai Change Caine';
    b64 = instance.encodeForBase64(s.getBytes(), true);
    debug(b64);
    bytes = instance.decodeFromBase64(b64);
    debug(bytes);
    assertEquals( arrayLen(bytes) , arrayLen(s.getBytes()) );

    /* try { for ( int i=0; i < 100; i++ ) {
         byte[] r = ESAPI.randomizer().getRandomString( 20, DefaultEncoder.CHAR_SPECIALS ).getBytes();
         String encoded = instance.encodeForBase64( r, ESAPI.randomizer().getRandomBoolean() );
         byte[] decoded = instance.decodeFromBase64( encoded );
         assertTrue( Arrays.equals( r, decoded ) );
     }
     } catch ( IOException e ) {
         fail();
     }
    */
  }



   function testEncodeForLDAP() {
        debug("encodeForLDAP");
        assertEquals(null, instance.encodeForLDAP(null));
        assertEquals("Hi This is a test ##��", instance.encodeForLDAP("Hi This is a test ##��"));
        assertEquals('Hi \5cu0000', instance.encodeForLDAP("Hi \u0000"));
        assertEquals('Hi \28This\29 = is \2a a \5c test ## � � �', instance.encodeForLDAP("Hi (This) = is * a \ test ## � � �"));
   }

   function testEncodeForDN() {
        debug("encodeForDN");
        assertEquals(null, instance.encodeForDN(null));
        assertEquals("Hello�", instance.encodeForDN("Hello�") , "No special characters to escape" );
        assertEquals("\## Hello�", instance.encodeForDN("## Hello�"),"leading ##" );
        assertEquals("\ Hello�", instance.encodeForDN(" Hello�") , "leading space");
        assertEquals("Hello�\ ", instance.encodeForDN("Hello� "), "trailing space");
        assertEquals("Hello\<\>", instance.encodeForDN("Hello<>") , "less than greater than");
        assertEquals("\  \ ", instance.encodeForDN("   ") , "only 3 spaces");
        assertEquals('\ Hello\\ \+ \, \"World\" \;\ ', instance.encodeForDN(' Hello\ + , "World" ; ') , "Christmas Tree DN");
    }

  function testEncodeForXPath() {
      debug("encodeForXPath");
      assertEquals(null, instance.encodeForXPath(null));
      assertEquals("&##x27;or 1&##x3d;1", instance.encodeForXPath("'or 1=1"));
  }

 function testNormalize() {
	debug("normalize");
	debug('define charset maybe?');
	assertEquals( 'e a i _ @ \" < > ', encoder.normalize('� � � _ @ " < > \u20A0'));
 }


   function testEncodeForVBScript() {
        debug("encodeForVBScript");
        assertEquals(null, instance.encodeForVBScript(null));
        assertEquals( 'chrw(60)&"script"&chrw(62)', instance.encodeForVBScript("<script>"));
        assertEquals( 'x"&chrw(32)&chrw(33)&chrw(64)&chrw(36)&chrw(37)&chrw(40)&chrw(41)&chrw(61)&chrw(43)&chrw(123)&chrw(125)&chrw(91)&chrw(93)', instance.encodeForVBScript("x !@$%()=+{}[]"));
        assertEquals( 'alert"&chrw(40)&chrw(39)&"ESAPI"&chrw(32)&"test"&chrw(33)&chrw(39)&chrw(41)', instance.encodeForVBScript("alert('ESAPI test!')" ));
        assertEquals( 'jeff.williams"&chrw(64)&"aspectsecurity.com', instance.encodeForVBScript("jeff.williams@aspectsecurity.com"));
        assertEquals( 'test"&chrw(32)&chrw(60)&chrw(62)&chrw(32)&"test', instance.encodeForVBScript("test <> test" ));
    }


 //To Do: Need to pass java obj via CF
 function testEncodeForSQL() {
 	debug("encodeForSQL");
 	fail('Erroring on passing Java type to encodeForSQL. Talk w/Marc. ');
 	classLoader = createObject('component' , root & 'cfesapi.org.owasp.esapi.ClassLoader').init();
    loader = classLoader.loadClasses();
    MySQLCodec = loader.create('org.owasp.esapi.codecs.MySQLCodec');//.init();
    mySQL1 = MySQLCodec.init(MySQLCodec.ANSI_MODE);
    //debug(mySQL1);
    assertEquals("ANSI_MODE", null, instance.encodeForSQL(mySQL1, null));

    assertEquals("ANSI_MODE", "Jeff'' or ''1''=''1", instance.encodeForSQL(mySQL1, "Jeff' or '1'='1"));

    mySQL2 = MySQLCodec.init( MySQLCodec.MYSQL_MODE );
    assertEquals("MYSQL_MODE", null, instance.encodeForSQL(mySQL2, null));
    assertEquals("MYSQL_MODE", "Jeff\\' or \\'1\\'\\=\\'1", instance.encodeForSQL(mySQL2, "Jeff' or '1'='1"));

    oracle = loader.create('org.owasp.esapi.codecs.OracleCodec');;
    assertEquals("Oracle", null, instance.encodeForSQL(oracle, null));
    assertEquals("Oracle", "Jeff\\' or \\'1\\'\\=\\'1", instance.encodeForSQL(oracle, "Jeff' or '1'='1"));

    }

  function testEncodeForXMLAttribute() {
      debug("encodeForXMLAttribute");
      assertEquals(null, instance.encodeForXMLAttribute(null));
      assertEquals("&##x20;", instance.encodeForXMLAttribute(" "));
      assertEquals("&lt;script&gt;", instance.encodeForXMLAttribute("<script>"));
      assertEquals(",.-_", instance.encodeForXMLAttribute(",.-_"));
      assertEquals("&##x20;&##x21;&##x40;&##x24;&##x25;&##x28;&##x29;&##x3d;&##x2b;&##x7b;&##x7d;&##x5b;&##x5d;", instance.encodeForXMLAttribute(" !@$%()=+{}[]"));
    }


   function testEncodeForXML() {
       debug("encodeForXML");
       assertEquals(null, instance.encodeForXML(null));
       assertEquals(" ", instance.encodeForXML(" "));
       assertEquals("&lt;script&gt;", instance.encodeForXML("<script>"));
       assertEquals(",.-_", instance.encodeForXML(",.-_"));
       assertEquals("&##x21;&##x40;&##x24;&##x25;&##x28;&##x29;&##x3d;&##x2b;&##x7b;&##x7d;&##x5b;&##x5d;", instance.encodeForXML("!@$%()=+{}[]"));
   }


  function testEncodeForURL() {
        debug("encodeForURL");
        assertEquals(null, instance.encodeForURL(null));
        assertEquals("%3Cscript%3E", instance.encodeForURL("<script>"));
    }

  function testDecodeFromURL(){
     debug("decodeFromURL");
     assertEquals(null, instance.decodeFromURL(null));
     assertEquals("<script>", instance.decodeFromURL("%3Cscript%3E"));
     assertEquals("     ", instance.decodeFromURL("+++++") );
  }

 function testEncodeForHTMLAttribute() {
        debug("encodeForHTMLAttribute");
        assertEquals(null, instance.encodeForHTMLAttribute(null));
        assertEquals("&lt;script&gt;", instance.encodeForHTMLAttribute("<script>"));
        assertEquals(",.-_", instance.encodeForHTMLAttribute(",.-_"));
        assertEquals("&##x20;&##x21;&##x40;&##x24;&##x25;&##x28;&##x29;&##x3d;&##x2b;&##x7b;&##x7d;&##x5b;&##x5d;", instance.encodeForHTMLAttribute(" !@$%()=+{}[]"));
    }

function testEncodeForCSS(){
    debug("encodeForJavascript");
    assertEquals(null, encoder.encodeForCSS(null));
    assertEquals(null, encoder.encodeForCSS(null));
    assertEquals("\3c script\3e ", encoder.encodeForCSS("<script>"));
    assertEquals("\21 \40 \24 \25 \28 \29 \3d \2b \7b \7d \5b \5d ", encoder.encodeForCSS("!@$%()=+{}[]"));
 }


 function testEncodeForJavaScript(){
    debug("encodeForJavascript");
    assertEquals(null, encoder.encodeForJavaScript(null));
    assertEquals("\x3Cscript\x3E", encoder.encodeForJavaScript("<script>"));
    assertEquals(",.\x2D_\x20", encoder.encodeForJavaScript(",.-_ "));
    assertEquals("\x21\x40\x24\x25\x28\x29\x3D\x2B\x7B\x7D\x5B\x5D", encoder.encodeForJavaScript("!@$%()=+{}[]"));
    assertEquals( "\x5c0", encoder.encodeForJavaScript("\0"));
    assertEquals( "\x5cb", encoder.encodeForJavaScript("\b"));
    assertEquals( "\x5ct", encoder.encodeForJavaScript("\t"));
    assertEquals( "\x5cn", encoder.encodeForJavaScript("\n"));
   // assertEquals( "\v", encoder.encodeForJavaScript("" + (char)'0x0b'));
    assertEquals( "\x5cf", encoder.encodeForJavaScript("\f"));
    assertEquals( "\x5cr", encoder.encodeForJavaScript("\r"));
    assertEquals( "\x27", encoder.encodeForJavaScript("'"));
    assertEquals( "\x5c", encoder.encodeForJavaScript("\"));
    assertEquals( '\x22', encoder.encodeForJavaScript('"'));
    assertEquals( "\x5c\x5c", encoder.encodeForJavaScript("\\"));

 }



 function testDoubleEncodingCanonicalization() {
        debug("doubleEncodingCanonicalization");
        // note these examples use the strict=false flag on canonicalize to allow
        // full decoding without throwing an IntrusionException. Generally, you
        // should use strict mode as allowing double-encoding is an abomination.

        // double encoding examples
        assertEquals( "<", instance.canonicalize("&##x26;lt&##59", false )); //double entity
        assertEquals( "\", instance.canonicalize("%255c", false)); //double percent
        assertEquals( "%", instance.canonicalize("%2525", false)); //double percent

        // double encoding with multiple schemes example
        assertEquals( "<", instance.canonicalize("%26lt%3b", false)); //first entity, then percent
        assertEquals( "&", instance.canonicalize("&##x25;26", false)); //first percent, then entity

        // nested encoding examples
        assertEquals( "<", instance.canonicalize("%253c", false)); //nested encode % with percent
        assertEquals( "<", instance.canonicalize("%%33%63", false)); //nested encode both nibbles with percent
        assertEquals( "<", instance.canonicalize("%%33c", false)); // nested encode first nibble with percent
        assertEquals( "<", instance.canonicalize("%3%63", false));  //nested encode second nibble with percent
        assertEquals( "<", instance.canonicalize("&&##108;t;", false)); //nested encode l with entity
        assertEquals( "<", instance.canonicalize("%2&##x35;3c", false)); //triple percent, percent, 5 with entity

        // nested encoding with multiple schemes examples
        assertEquals( "<", instance.canonicalize("&%6ct;", false)); // nested encode l with percent
        assertEquals( "<", instance.canonicalize("%&##x33;c", false)); //nested encode 3 with entity

        // multiple encoding tests
        assertEquals( "% & <script> <script>", instance.canonicalize( "%25 %2526 %26##X3c;script&##x3e; &##37;3Cscript%25252525253e", false ) );
        assertEquals( "< < < < < < <", instance.canonicalize( "%26lt; %26lt; &##X25;3c &##x25;3c %2526lt%253B %2526lt%253B %2526lt%253B", false ) );

        // test strict mode with both mixed and multiple encoding
        try {
            assertEquals( "< < < < < < <", instance.canonicalize( "%26lt; %26lt; &##X25;3c &##x25;3c %2526lt%253B %2526lt%253B %2526lt%253B" ) );
        } catch( org.owasp.esapi.errors.IntrusionException e ) {
            // expected
        }

        try {
            assertEquals( "<script", instance.canonicalize("%253Cscript" ) );
        } catch( org.owasp.esapi.errors.IntrusionException e ) {
            // expected
        }
        try {
            assertEquals( "<script", instance.canonicalize("&##37;3Cscript" ) );
        } catch( org.owasp.esapi.errors.IntrusionException e ) {
            // expected
        }


    }



 function testEncodeForHTML(){

   // test invalid characters are replaced with spaces
   //to do: assertEquals("a b c d e f&#x9;g", encoder.encodeForHTML("a" + (char) 0 + "b" + (char) 4 + "c" + (char) 128 + "d" + (char) 150 + "e" + (char) 159 + "f" + (char) 9 + "g"));

     assertEquals("&lt;script&gt;", encoder.encodeForHTML("<script>"));
     assertEquals("&amp;lt&##x3b;script&amp;gt&##x3b;", encoder.encodeForHTML("&lt;script&gt;"));
     assertEquals("&##x21;&##x40;&##x24;&##x25;&##x28;&##x29;&##x3d;&##x2b;&##x7b;&##x7d;&##x5b;&##x5d;", encoder.encodeForHTML("!@$%()=+{}[]"));
     assertEquals("&##x21;&##x40;&##x24;&##x25;&##x28;&##x29;&##x3d;&##x2b;&##x7b;&##x7d;&##x5b;&##x5d;", encoder.encodeForHTML(encoder.canonicalize("&##33;&##64;&##36;&##37;&##40;&##41;&##61;&##43;&##123;&##125;&##91;&##93;")));
     assertEquals(",.-_ ", encoder.encodeForHTML(",.-_ "));
     assertEquals("dir&amp;", encoder.encodeForHTML("dir&"));
     assertEquals("one&amp;two", encoder.encodeForHTML("one&two"));
     //to do: assertEquals("" + (char) 12345 + (char) 65533 + (char) 1244, "" + (char) 12345 + (char) 65533 + (char) 1244);


 }

  function testCannonicalize(){
       var null = chr(0);
       debug('direct port of test from ref impl.');

     // Test null paths
        assertEquals(null, encoder.canonicalize(null));
        assertEquals(null, encoder.canonicalize(null, true));
        assertEquals(null, encoder.canonicalize(null, false));

        // test exception paths
        assertEquals("%", encoder.canonicalize("%25", true));
        assertEquals("%", encoder.canonicalize("%25", false));

        assertEquals("%", encoder.canonicalize("%25"));
        assertEquals("%F", encoder.canonicalize("%25F"));
        assertEquals("<", encoder.canonicalize("%3c"));
        assertEquals("<", encoder.canonicalize("%3C"));
        assertEquals("%X1", encoder.canonicalize("%X1"));

        assertEquals("<", encoder.canonicalize("&lt"));
        assertEquals("<", encoder.canonicalize("&LT"));
        assertEquals("<", encoder.canonicalize("&lt;"));
        assertEquals("<", encoder.canonicalize("&LT;"));

        assertEquals("%", encoder.canonicalize("&##37;"));
        assertEquals("%", encoder.canonicalize("&##37"));
        assertEquals("%b", encoder.canonicalize("&##37b"));

        assertEquals("<", encoder.canonicalize("&##x3c"));
        assertEquals("<", encoder.canonicalize("&##x3c;"));
        assertEquals("<", encoder.canonicalize("&##x3C"));
        assertEquals("<", encoder.canonicalize("&##X3c"));
        assertEquals("<", encoder.canonicalize("&##X3C"));
        assertEquals("<", encoder.canonicalize("&##X3C;"));

        // percent encoding
        assertEquals("<", encoder.canonicalize("%3c"));
        assertEquals("<", encoder.canonicalize("%3C"));

        // html entity encoding
        assertEquals("<", encoder.canonicalize("&##60"));
        assertEquals("<", encoder.canonicalize("&##060"));
        assertEquals("<", encoder.canonicalize("&##0060"));
        assertEquals("<", encoder.canonicalize("&##00060"));
        assertEquals("<", encoder.canonicalize("&##000060"));
        assertEquals("<", encoder.canonicalize("&##0000060"));
        assertEquals("<", encoder.canonicalize("&##60;"));
        assertEquals("<", encoder.canonicalize("&##060;"));
        assertEquals("<", encoder.canonicalize("&##0060;"));
        assertEquals("<", encoder.canonicalize("&##00060;"));
        assertEquals("<", encoder.canonicalize("&##000060;"));
        assertEquals("<", encoder.canonicalize("&##0000060;"));
        assertEquals("<", encoder.canonicalize("&##x3c"));
        assertEquals("<", encoder.canonicalize("&##x03c"));
        assertEquals("<", encoder.canonicalize("&##x003c"));
        assertEquals("<", encoder.canonicalize("&##x0003c"));
        assertEquals("<", encoder.canonicalize("&##x00003c"));
        assertEquals("<", encoder.canonicalize("&##x000003c"));
        assertEquals("<", encoder.canonicalize("&##x3c;"));
        assertEquals("<", encoder.canonicalize("&##x03c;"));
        assertEquals("<", encoder.canonicalize("&##x003c;"));
        assertEquals("<", encoder.canonicalize("&##x0003c;"));
        assertEquals("<", encoder.canonicalize("&##x00003c;"));
        assertEquals("<", encoder.canonicalize("&##x000003c;"));
        assertEquals("<", encoder.canonicalize("&##X3c"));
        assertEquals("<", encoder.canonicalize("&##X03c"));
        assertEquals("<", encoder.canonicalize("&##X003c"));
        assertEquals("<", encoder.canonicalize("&##X0003c"));
        assertEquals("<", encoder.canonicalize("&##X00003c"));
        assertEquals("<", encoder.canonicalize("&##X000003c"));
        assertEquals("<", encoder.canonicalize("&##X3c;"));
        assertEquals("<", encoder.canonicalize("&##X03c;"));
        assertEquals("<", encoder.canonicalize("&##X003c;"));
        assertEquals("<", encoder.canonicalize("&##X0003c;"));
        assertEquals("<", encoder.canonicalize("&##X00003c;"));
        assertEquals("<", encoder.canonicalize("&##X000003c;"));
        assertEquals("<", encoder.canonicalize("&##x3C"));
        assertEquals("<", encoder.canonicalize("&##x03C"));
        assertEquals("<", encoder.canonicalize("&##x003C"));
        assertEquals("<", encoder.canonicalize("&##x0003C"));
        assertEquals("<", encoder.canonicalize("&##x00003C"));
        assertEquals("<", encoder.canonicalize("&##x000003C"));
        assertEquals("<", encoder.canonicalize("&##x3C;"));
        assertEquals("<", encoder.canonicalize("&##x03C;"));
        assertEquals("<", encoder.canonicalize("&##x003C;"));
        assertEquals("<", encoder.canonicalize("&##x0003C;"));
        assertEquals("<", encoder.canonicalize("&##x00003C;"));
        assertEquals("<", encoder.canonicalize("&##x000003C;"));
        assertEquals("<", encoder.canonicalize("&##X3C"));
        assertEquals("<", encoder.canonicalize("&##X03C"));
        assertEquals("<", encoder.canonicalize("&##X003C"));
        assertEquals("<", encoder.canonicalize("&##X0003C"));
        assertEquals("<", encoder.canonicalize("&##X00003C"));
        assertEquals("<", encoder.canonicalize("&##X000003C"));
        assertEquals("<", encoder.canonicalize("&##X3C;"));
        assertEquals("<", encoder.canonicalize("&##X03C;"));
        assertEquals("<", encoder.canonicalize("&##X003C;"));
        assertEquals("<", encoder.canonicalize("&##X0003C;"));
        assertEquals("<", encoder.canonicalize("&##X00003C;"));
        assertEquals("<", encoder.canonicalize("&##X000003C;"));

        assertEquals("<", encoder.canonicalize("&lt"));
        assertEquals("<", encoder.canonicalize("&lT"));
        assertEquals("<", encoder.canonicalize("&Lt"));
        assertEquals("<", encoder.canonicalize("&LT"));
        assertEquals("<", encoder.canonicalize("&lt;"));
        assertEquals("<", encoder.canonicalize("&lT;"));
        assertEquals("<", encoder.canonicalize("&Lt;"));
        assertEquals("<", encoder.canonicalize("&LT;"));

  }



  function setUp(){
    encoder = createObject('component', root & 'cfesapi.org.owasp.esapi.Encoder').init();
    instance = encoder;
    someCharsToTest = getEncodedCharacters();
  }

  function tearDown(){

  }


</cfscript>

<cffunction name="testEncoderdsWithMxunitDataProvider" mxunit:data="someCharsToTest">
  <cfargument name="q">
  <cfset assertEquals("<", encoder.canonicalize( q.encoded ) , 'Failure at row  #q.currentrow#') />
</cffunction>

<!--- <cffunction name="testAllOpenBracketPermuationsWithCFEncodeFunction">
 <cfset q = getEncodedCharacters()>
 <cfoutput query="q">
 #q.currentRow#. #q.encoded# #htmlEditFormat(q.encoded)# #urlEncodedFormat(q.encoded)#
 <br />
 </cfoutput>
</cffunction> --->

<cffunction name="testAllOpenBracketPermuations">
 <cfset q = getEncodedCharacters()>
 <cfoutput query="q">
  <cfset assertEquals("<", encoder.canonicalize( q.encoded ) , 'Failure at row  #q.currentrow#') />
 </cfoutput>
</cffunction>

<cffunction name="getEncodedCharacters" access="private" hint="These are from snake @ ha.ckers.org">
<cf_querysim>
encodedChars
encoded
&lt;
%3C
%3c
&lt
&lt;
&LT
&LT;
&#60
&#060
&#0060
&#00060
&#000060
&#0000060
&#60;
&#060;
&#0060;
&#00060;
&#000060;
&#0000060;
&#x3c
&#x03c
&#x003c
&#x0003c
&#x00003c
&#x000003c
&#x3c;
&#x03c;
&#x003c;
&#x0003c;
&#x00003c;
&#x000003c;
&#X3c
&#X03c
&#X003c
&#X0003c
&#X00003c
&#X000003c
&#X3c;
&#X03c;
&#X003c;
&#X0003c;
&#X00003c;
&#X000003c;
&#x3C
&#x03C
&#x003C
&#x0003C
&#x00003C
&#x000003C
&#x3C;
&#x03C;
&#x003C;
&#x0003C;
&#x00003C;
&#x000003C;
&#X3C
&#X03C
&#X003C
&#X0003C
&#X00003C
&#X000003C
&#X3C;
&#X03C;
&#X003C;
&#X0003C;
&#X00003C;
&#X000003C;
\x3c
\x3C
\u003c
\u003C
</cf_querysim>
 <cfreturn encodedChars />
</cffunction>



</cfcomponent>